package br.org.jbrisa.upnp.controlpoint;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import br.org.jbrisa.upnp.JBRisaUPnPConstants;
import br.org.jbrisa.upnp.UPnPDefaults;
import br.org.jbrisa.upnp.controlpoint.event.EventListenerServer;
import br.org.jbrisa.upnp.controlpoint.event.MulticastEventListener;
import br.org.jbrisa.upnp.controlpoint.msearch.MSearch;
import br.org.jbrisa.upnp.device.Device;
import br.org.jbrisa.upnp.ssdp.SSDPServer;

public abstract class ControlPoint {
	
	private SSDPServer ssdpServer;
	
	private MSearch mSearch;
	
	private EventListenerServer eventListener;
	
	private MulticastEventListener multicastEventListener;
	
	private Map<String, Device> knownDevices;
	
	//TODO callbacks - como tratar?
	
	public ControlPoint(boolean receiveNotify) {
		this.ssdpServer = new SSDPServer("BRisa Control Point", null, JBRisaUPnPConstants.SSDPMaxAge, receiveNotify);
		
		//TODO subscribe- comofas?
		
		this.mSearch = new MSearch(this.ssdpServer, false, UPnPDefaults.MSEARCH_DEFAULT_SEARCH_TIME,
				UPnPDefaults.SSDP_ADDR, UPnPDefaults.SSDP_PORT);
		
		this.eventListener = new EventListenerServer(this);
		
		this.multicastEventListener = new MulticastEventListener(this, false);
		
		this.knownDevices = new HashMap<String, Device>();
	}
	
	public boolean isRunning() {
		return this.getSsdpServer().isRunning() && 
				this.getEventListener().isRunning() && 
				this.getMulticastEventListener().isRunning();
	}
	
	public void start() {
		if (!this.isRunning()) {
			this.getSsdpServer().start();
			this.getEventListener().start();
			this.getMulticastEventListener().start();
		} else {
			//TODO logar JBRisaUPnPConstants.msgAlreadyStarted 
		}
	}
	
	public void stop() {
		if (this.isRunning()) {
			if (this.isMSearchRunning()) {
				this.stopSearch();
			}
			this.getSsdpServer().stop();
			this.getEventListener().stop();
			this.getMulticastEventListener().stop();
		} else {
			//TODO logar JBRisaUPnPConstants.msgAlreadyStopped
		}
	}
	
	public void subscribe() {
		//TODO comofas?
	}
	
	public void unsubscribe() {
		//TODO comofas?
	}
	
	public void startSearch(float interval, String searchType, boolean reset) {
		if (reset) {
			this.getSsdpServer().clearDeviceList();
		}
		this.getMSearch().start(interval, searchType);
	}	

	public void stopSearch() {
		this.getMSearch().stop();
	}
	
	public void forceDiscovery(String searchType) {
		this.getMSearch().doubleDiscovery(searchType);
	}

	public boolean isMSearchRunning() {
		return this.getMSearch().isRunning();
	}
	
	private void newDeviceEvent(String deviceType, Map<String, String> deviceInfo) {
		if (deviceInfo.containsKey("LOCATION")) {
//			TODO callbacks?
//			CPDevice.getFromLocationAsync(deviceInfo.get("LOCATION"), )
		}
	}
	
	private void removedDeviceEvent(Map<String, String> deviceInfo) {
		String udn = deviceInfo.get("UDN");
		if (this.getKnownDevices().containsValue(udn)) {
			//TODO logar "Device is gone " + this.getKnownDevices().get(udn).friendlyName() 
		}
		
		this.getKnownDevices().remove(udn);
		//TODO self._callback("removed_device_event", udn)
	}
	
	private void onEvent(String serviceId, Collection changedVars) {
		//TODO self._callback("device_event", sid, changed_vars)
	}

	public MSearch getMSearch() {
		return mSearch;
	}
	
	public void setMSearch(MSearch search) {
		mSearch = search;
	}
	
	public SSDPServer getSsdpServer() {
		return ssdpServer;
	}

	public void setSsdpServer(SSDPServer ssdpServer) {
		this.ssdpServer = ssdpServer;
	}

	public EventListenerServer getEventListener() {
		return eventListener;
	}

	public void setEventListener(EventListenerServer eventListener) {
		this.eventListener = eventListener;
	}

	public MulticastEventListener getMulticastEventListener() {
		return multicastEventListener;
	}

	public void setMulticastEventListener(
			MulticastEventListener multicastEventListener) {
		this.multicastEventListener = multicastEventListener;
	}

	public Map<String, Device> getKnownDevices() {
		return knownDevices;
	}

	public void setKnownDevices(Map<String, Device> knownDevices) {
		this.knownDevices = knownDevices;
	}
	
}
